﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace PushNotifications.WinRT
{
    public class NotificationSender
    {
        private string accessToken;

        public NotificationSender()
        {
        }

        public string Sid { get; set; }

        public string SecretKey { get; set; }

        protected void GetAccessToken()
        {
            var urlEncodedSid = HttpUtility.UrlEncode(String.Format("{0}", Sid));
            var urlEncodedSecret = HttpUtility.UrlEncode(SecretKey);

            var body =
              String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com", urlEncodedSid, urlEncodedSecret);

            var client = new WebClient();
            client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

            string response = client.UploadString("https://login.live.com/accesstoken.srf", body);
            var oAuthToken = OAuthToken.GetOAuthTokenFromJson(response);
            accessToken = oAuthToken.AccessToken;
        }

        protected NotificationResult PostToCloud(string uri, INotificationMessage message)
        {
            try
            {
                byte[] contentInBytes = Encoding.UTF8.GetBytes(message.GetContent());

                WebRequest webRequest = HttpWebRequest.Create(uri);
                HttpWebRequest request = webRequest as HttpWebRequest;
                webRequest.Method = "POST";
                webRequest.ContentType = "text/xml";
                webRequest.Headers.Add("X-WNS-Type", message.Type.GetKey());
                webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
                webRequest.Headers.Add("X-WNS-Cache-Policy", message.CachePolicy.GetKey());

                webRequest.Headers.Add("X-WNS-RequestForStatus", message.RquestForStatus ? "true" : "false");
                if (message.Type == NotificationType.Tile)
                    webRequest.Headers.Add("X-WNS-Tag", message.Tag);

                if (message.TTL.HasValue)
                    webRequest.Headers.Add("X-WNS-TTL", message.TTL.Value.ToString());

                using (Stream requestStream = webRequest.GetRequestStream())
                    requestStream.Write(contentInBytes, 0, contentInBytes.Length);
                

                HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
                var result = new NotificationResult();
                switch (webResponse.StatusCode)
                {
                    case HttpStatusCode.OK:
                        result.ServiceResult = ServiceResult.Ok;
                        break;
                    case HttpStatusCode.BadRequest:
                        result.ServiceResult = ServiceResult.BadRequest;
                        break;
                    case HttpStatusCode.Unauthorized:
                        result.ServiceResult = ServiceResult.UnAutorized;
                        break;
                    case HttpStatusCode.Forbidden:
                        result.ServiceResult = ServiceResult.Forbidden;
                        break;
                    case HttpStatusCode.NotFound:
                        result.ServiceResult = ServiceResult.NotFound;
                        break;
                    case HttpStatusCode.MethodNotAllowed:
                        result.ServiceResult = ServiceResult.MethodNotAllowed;
                        break;
                    case HttpStatusCode.NotAcceptable:
                        result.ServiceResult = ServiceResult.NotAcceptable;
                        break;
                    case HttpStatusCode.Gone:
                        result.ServiceResult = ServiceResult.Gone;
                        break;
                    case HttpStatusCode.RequestEntityTooLarge:
                        result.ServiceResult = ServiceResult.RequestEntityTooLarge;
                        break;
                    case HttpStatusCode.InternalServerError:
                        result.ServiceResult = ServiceResult.InternalServerError;
                        break;
                    case HttpStatusCode.ServiceUnavailable:
                        result.ServiceResult = ServiceResult.ServiceUnavailable;
                        break;
                }
                return result;
            }
            catch (WebException webException)
            {
                string exceptionDetails = webException.Response.Headers["WWW-Authenticate"];
                if (exceptionDetails.Contains("Token expired"))
                {
                    GetAccessToken();
                    return PostToCloud(uri, message);
                }
                else
                {
                    throw;
                }
            }
        }
    }
}
